// Author: 		ngohaibac@hocdelam.org
// Date:		20th Nov, 2009
// Hardware:	TMS320F28335
// Module:		EQep Module	
#include "DSP2833x_System.h"

#include "DSP2833x_EQepLib.h"

// Declare some local functions
void InitEQepGpio(void);
#if DSP28_EQEP1
	void InitEQep1Gpio(void);
#endif	
#if DSP28_EQEP2
	void InitEQep2Gpio(void);
#endif	

// Declare some structures and enums

volatile struct EQEP_REGS * EQepRegs_Array[] = {&EQep1Regs, &EQep2Regs};
void (* InitEQepGpio_Fcns[])(void)  = {&InitEQep1Gpio, InitEQep2Gpio};

//=========================================
// Reading results
//=========================================

// Read position for Position control
Uint32 EQep_ReadPosition(enum EQep_Group EQep,enum EQep_Control_Type Control_Type){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];
	
	switch(Control_Type){	
		case EQep_Position_Control:		// Return actual position
			return(EQepRegs->QPOSCNT);			
		case EQep_Speed_Control:		// Return latch register
			return(EQepRegs->QPOSLAT);			
	}
	return 0;	
}
// Read EQep Direction
Uint16 EQep_ReadDirection(enum EQep_Group EQep){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];
	return (EQepRegs->QEPSTS.bit.QDF);
}

// Read capture value
Uint32 EQep_ReadECPValue(enum EQep_Group EQep){
	// check if overflow => ...
	
	// check if upper flow => ...
	
	return 0;
	
}
//==========================================
// EQep Initialize: For Position control
// Reset on first Index Event
// Init by software
//==========================================
void EQep_Init(enum EQep_Group EQep, enum EQep_Control_Type control_type){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];
	
	union  QDECCTL_REG  QDECCTLShadow;
	union  QEPCTL_REG   QEPCTLShadow;
	union  QPOSCTL_REG  QPOSCTLShadow;
	   
	//-------------------------------------------------
	// Step 1: Initialize GPIO for EQep Module
	//-------------------------------------------------
	//(*InitEQepGpio_Fcns[EQep])();
	
	InitEQepGpio();
	
	//-------------------------------------------------
	// Step 2: Quadrature Decoder Unit
	// 		Setup for input EQepA, EQepB, EQepI, EQepS
	//-------------------------------------------------

	// Invert input pins; 0: No effect, 1: Negates
	QDECCTLShadow.bit.QAP = 0; 				//QEAP input polarity
	QDECCTLShadow.bit.QBP = 0;				//QEBP input polarity
	QDECCTLShadow.bit.QIP = 1;				//QEIP input polarity
	QDECCTLShadow.bit.QSP = 0;				//QEPS input polarity
				
	
	// QEQPxAIN, QEQPxBIN
	QDECCTLShadow.bit.QSRC = 0;
				// 00: Quadrature count mode (QCLK = iCLK, QDIR = iDIR)
				// 01: Direction-count mode (QCLK = xCLK, QDIR = xDIR)
				// 10: Up count mode for frequency measurement (QCLK = xCLK, QDIR = 1)
				// 11: DOWN count mode for frequency measurement (QCLK = xCLK, QDIR = 0)
				
	QDECCTLShadow.bit.XCR = 0; 						// External clock rate for <strong>mode: 01,10,11 </strong>				
				// 0: 2x resolution: count on rising/falling edge
				// 1: 1x resolution: count the rising edge only
				
	QDECCTLShadow.bit.SWAP = 1;						// Swap QA and QB
				// 0: not swapped
				// 1: swapped
	// Quadrature Index and Strobe
	QDECCTLShadow.bit.IGATE = 1;
	
	// Sync output
	QDECCTLShadow.bit.SOEN = 0;			
				// 0: disable position-compare sync output, 
				// 1: enable position-compare sync output
	QDECCTLShadow.bit.SPSEL = 0;
				// 0: Index pin is used for sync output
				// 1: Strobe pin is used for sync output
	// Assign to the pointer
	EQepRegs->QDECCTL.all = QDECCTLShadow.all;

	//-------------------------------------------------
	// Step 3: Position Counter and Control Unit (PSCU)
	//-------------------------------------------------
	// Initialize Position init, maximum
	EQepRegs->QPOSINIT = QPOSInit_Val;				// Position counter init
	EQepRegs->QPOSMAX = QPOSMax_Val;					// Maximum position count
	
	// Enable quadrature position counter enable/software reset
	QEPCTLShadow.bit.QPEN = 0;					// Quadrature position counter enable/software reset
				// 0: Reset the eQEP peripheral internal operating flags/read-only registers. Control/configuratation 
				//		registers are not disturbed by a software reset
				// 1: eQEP position counter is enabled.
	
	
	QEPCTLShadow.bit.FREE_SOFT = 2;				// Emulation Control Bits
				// 00: Stop immediately
				// 01: Continue until next 
				// 1x: Unaffected by Emulation event
				
	//--------------------------------------------------
	// Position Counter Reset mode: QPOSCNT = 0 or QPOSMAX
	//--------------------------------------------------
	switch(control_type){
		case EQep_Position_Control:
			QEPCTLShadow.bit.PCRM = 2;
			break;
		case EQep_Speed_Control:
			QEPCTLShadow.bit.PCRM = 3;
			break;			
	};		
				// 00: Reset on an index event
				// 01: Reset on the maximum position
				// 10: Reset on the first index event
				// 11: Reset on a unit time event => Frequency measurement
	//--------------------------------------------------
	// Position Counter Latch
	//--------------------------------------------------
	QEPCTLShadow.bit.IEL = 0;					// Index event latch of position counter (software index maker)
				// QPOSCNT => QPOSILAT, ignored when PCRM = 00
				// 00: Reserved
				// 01: Latch on rising edge of the index signal
				// 10: Latch on falling edge of the index signal
				// 11: Latch on Index Event Maker/Software Index Maker
	QEPCTLShadow.bit.SEL = 0;					// Strobe event latch of position counter
				// QPOSCNT => QPOSSLAT
				// 0: Latched on rising edge of QEPS strobe
				// 1: Latched on: rising edge of CW dir, falling edge of OCW dir
	
	//--------------------------------------------------
	// Position Counter Initialization: QPOSCNT = QPOSINIT
	//--------------------------------------------------
	QEPCTLShadow.bit.IEI = 0;					// Index event initialization of position counter				
				// 00, 01: Does nothing
				// 10: Initializes on Rising edge of QEPI signal
				// 11: Initializes on Falling edge of QEPI signal
	QEPCTLShadow.bit.SEI = 0;
				// 00, 01: Does nothing
				// 10: Initializes on Rising edge of QEPS sginal
				// 11: Initializes base on Direction: rising for CW, falling for OCW				
	
	QEPCTLShadow.bit.SWI = 1;					// Sofware initialization of position counter
				// 0: Do nothing
				// 1: Initialize position counter, is cleared automatically	
				
	// Assign the QEPCTL
	EQepRegs->QEPCTL.all = QEPCTLShadow.all;
	
	// Enable QEP
	EQepRegs->QEPCTL.bit.QPEN = 1;
	
						
	//--------------------------------------------------
	// Step 4: Position-compare Unit: Don't use now: => PC Sync output: QPOSCNT = QPOSCMP
	//--------------------------------------------------
	EQepRegs->QPOSCMP = 0x0000;					// Position compare
	QPOSCTLShadow.bit.PCE = 0;					
				// 0: Disable position-compare unit
				// 1: Enable
	
	QPOSCTLShadow.bit.PCSHDW = 1;				// Position-compare shadow enable
				// 0: Disable
				// 1: Enable
	QPOSCTLShadow.bit.PCLOAD = 0;				// Position-compare load mode
				// 0: Load on QPOSCNT = 0
				// 1: Load when QPOSCNT = QPOSCMP				
	QPOSCTLShadow.bit.PCPOL = 0;				// Polarity of sync output					
				// 0: Active HIGH pulse output
				// 1: Active LOW pulse output
	QPOSCTLShadow.bit.PCSPW = 0;				// Position-compare sync output pulse width
				// Width = 2^x * 4 * SYCLCKOUT cycles
		
	// Assign the QPOSCTL
	EQepRegs->QPOSCTL.all = QPOSCTLShadow.all;	
	
}

void EQep_InitPositionCounter(enum EQep_Group EQep, Uint32 Position_Init){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];
	
	EQepRegs->QPOSINIT = Position_Init;
}

//===================================================
// Initialize Unit Time Base module: use for High Speed Velocity caculation
// Flag: QFLG:UTO (Time out flag)
// Unit Time Base clock from SYSCLKOUT
//===================================================
void EQep_InitUnitTimeBase(enum EQep_Group EQep, Uint32 UTB_Period){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];	
	
	// Change to reset when Time Out and Latch when Time Out
	//EQepRegs->QEPCTL.bit.PCRM = 3; 				//Reset on a unit time event => Frequency measurement
	
	// Setup Period of Timer
	EQepRegs->QUPRD = UTB_Period;					// Unit period
	
	// Enable/Disable Unit Time Base
	EQepRegs->QEPCTL.bit.UTE = 1;				// 0: Disable eQEP unit Timer, 1: Enable	
}
// For change the UTB period
void EQep_SetUTBPeriod(enum EQep_Group EQep, Uint32 UTB_Period){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];	
	
	// Disable UTB Module
	EQepRegs->QEPCTL.bit.UTE = 0;
	
	// Setup Period of Timer
	EQepRegs->QUPRD = UTB_Period;					// Unit period
	
	// Enable/Disable Unit Time Base
	EQepRegs->QEPCTL.bit.UTE = 1;				// 0: Disable eQEP unit Timer, 1: Enable	
}


//===================================================
// Init Capture Unit for Low speed calculation
// Check status Capture Over Flow or Direction Over Flow before reading the content
// Clock_Prescaler: 000 -> 111 (0->8)
// Position_Prescaler: 0000 -> 1011 (0 -> 11)
//===================================================
void EQep_InitEdgeCaptureUnit(enum EQep_Group EQep,Uint16 Clock_Prescaler, Uint16 Position_Prescaler ){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];		
	union  QCAPCTL_REG  QCAPCTLShadow; 
	
	QCAPCTLShadow.bit.CEN = 0; 							// Enable/Disable eQEP capture, 1: enable
	QCAPCTLShadow.bit.CCPS = Clock_Prescaler;			// Capture timer clock prescaler: 3 bits
				// CAPCLK = SYSCLKOUT/2^x
	QCAPCTLShadow.bit.UPPS = Position_Prescaler;		// Unit position event prescaler: should not be modified dynamically: 4 bits
				// UPEVENT = QCLK/2^X
	// Assign the register
	EQepRegs->QCAPCTL.all = QCAPCTLShadow.all;
	// Enable Unit Time Base module
	EQepRegs->QCAPCTL.bit.CEN = 1;
	
	// Latch mode: QCTMR => QCTMRLAT, QCPRD => QCPRDLAT
	EQepRegs->QEPCTL.bit.QCLM = 1;
				// 0: Latch on position counter read by CPU.
				// 1: Latch on unit time out: QPOSCNT => QPOSLAT, QCTMR => QCTMRLAT, QCPRD => QCPRDLAT	
								
}

void EQep_SetCaptureClock(enum EQep_Group EQep,Uint16 Clock_Prescaler){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];	
	// Disable CAP module
	EQepRegs->QCAPCTL.bit.CEN = 0;	
	// Change Capture Timer clock Prescaler
	EQepRegs->QCAPCTL.bit.CCPS = Clock_Prescaler;
	// Enable CAP module
	EQepRegs->QCAPCTL.bit.CEN = 1;
}

//=================================================
// Initialize EQep Interrupt
//=================================================
void EQep_InitInterrupt(enum EQep_Group EQep, Uint16 Interrupt_Channels, PINT Interrupt_Fcn){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];
	
	// Clear all Interrupt flags
	EQepRegs->QFLG.all = 0xFFFF;	
	// Enable Individual Interrupt
	EQepRegs->QEINT.all = Interrupt_Channels;	
	
	// Group 5 PIE	
	switch(EQep){
		case EQep1:
			PieCtrlRegs.PIEIER5.bit.INTx1 = 1;
			IER |= M_INT5;
			EALLOW;
			PieVectTable.EQEP1_INT = Interrupt_Fcn;
			EDIS;
			break;
		case EQep2:
			PieCtrlRegs.PIEIER5.bit.INTx2 = 1;
			IER |= M_INT5;
			EALLOW;
			PieVectTable.EQEP2_INT = Interrupt_Fcn;
			EDIS;		
			break;
	};
	
}

//==================================================
// Clear Interrupt Flag
//==================================================
void EQep_ClearIntFlags(enum EQep_Group EQep, enum EQep_Interrupt_Group EQep_Int_Type){
	volatile struct EQEP_REGS *EQepRegs = EQepRegs_Array[EQep];
	// Clear Global Int
	EQepRegs->QCLR.bit.INT = 1;
	// Clear corresponding int flag
	EQepRegs->QCLR.all = (1<<EQep_Int_Type);
	
	// Clear ACK
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP5;	
}


//---------------------------------------------------------------------------
// Example: InitEQepGpio:
//---------------------------------------------------------------------------
// This function initializes GPIO pins to function as eQEP pins
//
// Each GPIO pin can be configured as a GPIO pin or up to 3 different
// peripheral functional pins. By default all pins come up as GPIO
// inputs after reset.
//
// Caution:
// For each eQEP peripheral
// Only one GPIO pin should be enabled for EQEPxA operation.
// Only one GPIO pin should be enabled for EQEPxB operation.
// Only one GPIO pin should be enabled for EQEPxS operation.
// Only one GPIO pin should be enabled for EQEPxI operation.
// Comment out other unwanted lines.

void InitEQepGpio(void)
{
#if DSP28_EQEP1
   InitEQep1Gpio();
#endif  // endif DSP28_EQEP1
#if DSP28_EQEP2
   InitEQep2Gpio();
#endif // endif DSP28_EQEP2
}

#if DSP28_EQEP1
void InitEQep1Gpio(void)
{
   EALLOW;

/* Enable internal pull-up for the selected pins */
// Pull-ups can be enabled or disabled by the user.
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPAPUD.bit.GPIO20 = 0;   // Enable pull-up on GPIO20 (EQEP1A)
    GpioCtrlRegs.GPAPUD.bit.GPIO21 = 0;   // Enable pull-up on GPIO21 (EQEP1B)
//    GpioCtrlRegs.GPAPUD.bit.GPIO22 = 0;   // Enable pull-up on GPIO22 (EQEP1S)
//    GpioCtrlRegs.GPAPUD.bit.GPIO23 = 0;   // Enable pull-up on GPIO23 (EQEP1I)

//    GpioCtrlRegs.GPBPUD.bit.GPIO50 = 0;   // Enable pull-up on GPIO50 (EQEP1A)
//    GpioCtrlRegs.GPBPUD.bit.GPIO51 = 0;   // Enable pull-up on GPIO51 (EQEP1B)
    GpioCtrlRegs.GPBPUD.bit.GPIO52 = 0;   // Enable pull-up on GPIO52 (EQEP1S)
    GpioCtrlRegs.GPBPUD.bit.GPIO53 = 0;   // Enable pull-up on GPIO53 (EQEP1I)


// Inputs are synchronized to SYSCLKOUT by default.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPAQSEL2.bit.GPIO20 = 0;   // Sync to SYSCLKOUT GPIO20 (EQEP1A)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO21 = 0;   // Sync to SYSCLKOUT GPIO21 (EQEP1B)
//    GpioCtrlRegs.GPAQSEL2.bit.GPIO22 = 0;   // Sync to SYSCLKOUT GPIO22 (EQEP1S)
//    GpioCtrlRegs.GPAQSEL2.bit.GPIO23 = 0;   // Sync to SYSCLKOUT GPIO23 (EQEP1I)

//    GpioCtrlRegs.GPBQSEL2.bit.GPIO50 = 0;   // Sync to SYSCLKOUT GPIO50 (EQEP1A)
//    GpioCtrlRegs.GPBQSEL2.bit.GPIO51 = 0;   // Sync to SYSCLKOUT GPIO51 (EQEP1B)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO52 = 0;   // Sync to SYSCLKOUT GPIO52 (EQEP1S)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO53 = 0;   // Sync to SYSCLKOUT GPIO53 (EQEP1I)

/* Configure eQEP-1 pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be eQEP1 functional pins.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 1;   // Configure GPIO20 as EQEP1A
    GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 1;   // Configure GPIO21 as EQEP1B
//    GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 1;   // Configure GPIO22 as EQEP1S
//    GpioCtrlRegs.GPAMUX2.bit.GPIO23 = 1;   // Configure GPIO23 as EQEP1I

//    GpioCtrlRegs.GPBMUX2.bit.GPIO50 = 1;   // Configure GPIO50 as EQEP1A
//    GpioCtrlRegs.GPBMUX2.bit.GPIO51 = 1;   // Configure GPIO51 as EQEP1B
    GpioCtrlRegs.GPBMUX2.bit.GPIO52 = 1;   // Configure GPIO52 as EQEP1S
    GpioCtrlRegs.GPBMUX2.bit.GPIO53 = 1;   // Configure GPIO53 as EQEP1I

    EDIS;
}
#endif // if DSP28_EQEP1



#if DSP28_EQEP2
void InitEQep2Gpio(void)
{
   EALLOW;

/* Enable internal pull-up for the selected pins */
// Pull-ups can be enabled or disabled by the user.
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPAPUD.bit.GPIO24 = 0;    // Enable pull-up on GPIO24 (EQEP2A)
    GpioCtrlRegs.GPAPUD.bit.GPIO25 = 0;    // Enable pull-up on GPIO25 (EQEP2B)
    GpioCtrlRegs.GPAPUD.bit.GPIO26 = 0;    // Enable pull-up on GPIO26 (EQEP2I)
    GpioCtrlRegs.GPAPUD.bit.GPIO27 = 0;    // Enable pull-up on GPIO27 (EQEP2S)

// Inputs are synchronized to SYSCLKOUT by default.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPAQSEL2.bit.GPIO24 = 0;  // Sync to SYSCLKOUT GPIO24 (EQEP2A)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO25 = 0;  // Sync to SYSCLKOUT GPIO25 (EQEP2B)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO26 = 0;  // Sync to SYSCLKOUT GPIO26 (EQEP2I)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO27 = 0;  // Sync to SYSCLKOUT GPIO27 (EQEP2S)

/* Configure eQEP-2 pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be eQEP2 functional pins.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 2;   // Configure GPIO24 as EQEP2A
    GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 2;   // Configure GPIO25 as EQEP2B
    GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 2;   // Configure GPIO26 as EQEP2I
    GpioCtrlRegs.GPAMUX2.bit.GPIO27 = 2;   // Configure GPIO27 as EQEP2S


    EDIS;
}
#endif // endif DSP28_EQEP2




//===========================================================================
// End of file.
//===========================================================================
